import axios from 'axios'
import type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosRequestConfig } from 'axios'
import { getToken, setToken, isUrl } from './common';
import { message } from 'ant-design-vue';
import useUserStore from '@/stores/user';



interface RequestConfig extends AxiosRequestConfig {
    showErrorMessage?: boolean
    showSuccessMessage?: boolean
}

interface InternalRequestConfig extends InternalAxiosRequestConfig {
    showErrorMessage?: boolean
    showSuccessMessage?: boolean
}

interface requestResponse extends AxiosResponse {
    config: InternalRequestConfig
}

class Request {
    private instance: AxiosInstance;

    constructor() {
        this.instance = axios.create({
            baseURL: import.meta.env.VITE_APP_BASE_URL.substr(-1) == '/' ? import.meta.env.VITE_APP_BASE_URL : `${import.meta.env.VITE_APP_BASE_URL}/`,
            timeout: 50000,
            headers: {
                'Content-Type': 'application/json',
                'lang': 'zh-cn'
            }
        });

        // 全局请求拦截器
        this.instance.interceptors.request.use(
            (config: InternalRequestConfig) => {
                // 携带token
                if (getToken()) {
                    config.headers[import.meta.env.VITE_REQUEST_HEADER_TOKEN_KEY] = 'Bearer ' + getToken()
                }
                return config
            },
            (err: any) => {
                return Promise.reject(err)
            }
        )

        let isRefreshing = false;
        let pendingRequests: any[] = [];

        // 全局响应拦截器
        this.instance.interceptors.response.use(
            (response: requestResponse) => {
                if (response.request.responseType != 'blob') {
                    const res = response.data
                    if (res.code != 200) {
                        if (res.code == 401 && !isRefreshing) {
                            isRefreshing = true;

                            const userStore = useUserStore();
                            try {
                                axios.post(`${import.meta.env.VITE_APP_BASE_URL}passport/refresh`, { token: getToken() }).then(response => {
                                    if (response.status == 200 && response.data.code == 200) {
                                        // 保存新token
                                        setToken(response.data.data);
                                        isRefreshing = false;

                                        // 重试原始请求
                                        pendingRequests.forEach(callback => callback(response.data.data));
                                        pendingRequests = [];
                                        // return this.instance(response.config);
                                    } else {
                                        // 刷新出错了，重新登录
                                        userStore.logout();
                                        message.error('登录已失效，请重新登录', 5)
                                        return Promise.reject(new Error(res.message || 'Error'))
                                    }
                                }).catch(error => {
                                    // token过期太久，无法刷新，重新登录
                                    userStore.logout();
                                    return Promise.reject(error);
                                });
                            } catch (error) {
                                userStore.logout();
                                return Promise.reject(error);
                            }

                            if (isRefreshing) {
                                return new Promise((resolve) => {
                                    pendingRequests.push((token: string) => {
                                        response.config.headers[import.meta.env.VITE_REQUEST_HEADER_TOKEN_KEY] = 'Bearer ' + token
                                        resolve(this.instance(response.config))
                                    })
                                })
                            }
                        }
                        
                        message.error(res.message, 5)
                        return Promise.reject(new Error(res.message || 'Error'))
                    } else {
                        if (response.config.showSuccessMessage) {
                            message.success(res.message);
                        }
                        return res
                    }
                }
                return response.data
            },
            (err: any) => {
                this.handleNetworkError(err)
                return Promise.reject(err)
            }
        )
    }

    /**
     * 发送get请求
     * @param url
     * @param config
     * @returns
     */
    public get<T = any, R = AxiosResponse<T>>(url: string, config?: RequestConfig): Promise<R> {
        return this.instance.get(url, config)
    }

    /**
     * 发送post请求
     * @param url
     * @param config
     * @returns
     */
    public post<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: RequestConfig): Promise<R> {
        return this.instance.post(url, data, config)
    }

    /**
     * 发送put请求
     * @param url
     * @param config
     * @returns
     */
    public put<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: RequestConfig): Promise<R> {
        return this.instance.put(url, data, config)
    }

    /**
     * 发送delete请求
     * @param url
     * @param config
     * @returns
     */
    public delete<T = any, R = AxiosResponse<T>>(url: string, config?: RequestConfig): Promise<R> {
        return this.instance.delete(url, config)
    }

    /**
     * 处理网络请求错误
     * @param err
     */
    private handleNetworkError(err: any) {
        let errMessage = ''

        if (err.response && err.response.status) {
            const errStatus = err.response.status
            switch (errStatus) {
                case 400:
                    errMessage = "错误的请求"
                    break
                case 401:
                    errMessage = "请重新登录"
                    return;
                    break
                case 403:
                    errMessage = "拒绝访问"
                    break
                case 404:
                    const baseURL = isUrl(err.response.config.baseURL) ? err.response.config.baseURL : `${location.origin}${err.response.config.baseURL}`
                    errMessage = baseURL + "请求错误"
                    break
                case 405:
                    errMessage = "请求方法未允许"
                    break
                case 408:
                    errMessage = "请求超时"
                    break
                case 409:
                    errMessage = "请求跨域"
                    break
                case 500:
                    errMessage = "服务器端出错，错误原因："
                    break
                case 501:
                    errMessage = "网络未实现"
                    break
                case 502:
                    errMessage = "网络错误"
                    break
                case 503:
                    errMessage = "服务不可用"
                    break
                case 504:
                    errMessage = "网络超时"
                    break
                case 505:
                    errMessage = "http版本不支持该请求"
                    break
            }
        }
        err.message.includes('timeout') && (errMessage = "网络请求超时！")
        if (err.code == 'ERR_NETWORK') {
            const baseURL = isUrl(err.config.baseURL) ? err.config.baseURL : `${location.origin}${err.config.baseURL}`
            errMessage = baseURL + "接口请求错误"
        }
        errMessage && this.showGlobalMessage(errMessage)
    }

    private messageCache = new Map();

    // 全局错误提示
    private showGlobalMessage(errMessage: string) {
        const cacheKey = errMessage;
        const cachedMessage = this.messageCache.get(cacheKey);

        if (!cachedMessage || Date.now() - cachedMessage.timestamp > 5000) { // 5秒内重复内容不再弹出，可自定义过期时间
            this.messageCache.set(cacheKey, { timestamp: Date.now() });
            message.error(errMessage);
        }
    }
}

export default new Request()
